package com.saibo.spider.main;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.saibo.spider.commons.ConnectServer;
import com.saibo.spider.gather.Submitable;
import com.saibo.spider.gather.service.MissionService;
import com.saibo.spider.gather.service.ThreadService;
import com.saibo.spider.utils.IpConfigUtils;
import com.saibo.spider.utils.StringUtil;
import com.saibowisdom.base.api.aspirator.model.InfoClassMap;
import org.apache.commons.cli.*;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.log4j.Logger;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.GZIPOutputStream;

/**
 * 程序入口
 * 
 * @author zhangzhening
 *
 */
public class MainControl {

	public static Map<String, Object> missionMap = new HashMap<String, Object>();
	static Logger log = Logger.getLogger(MainControl.class);
	public static String MACADDRESS;
	static  MainControl mainControl = null;
	public static  String schedulerAddr="http://192.168.1.164:8081";
	public static String submitUrl = "http://192.168.1.164:8082";
	public static String dataServiceUrl = "http://192.168.1.210:8080/";
    //页面访问信息
    Map<Integer,Map<Integer,InfoClassMap>> sourceInfoMap= new HashMap<Integer, Map<Integer,InfoClassMap>>();

	public static List<Map<String, Object>> sourceList;

	final public static Map<String, String> threadNameMap = new ConcurrentHashMap();

	//public static Queue<Map<String, Object>> sourceQueue = new ArrayBlockingQueue<Map<String, Object>>(200);

	public static Map<String, List<String>> dataMap = new ConcurrentHashMap<String, List<String>>();

	public static Map<Integer,ArrayBlockingQueue<Map<String, Object>>> sourceMap = new ConcurrentHashMap<Integer, ArrayBlockingQueue<Map<String, Object>>>();


	private Map<String,ThreadService> mapThreads = new HashMap<String, ThreadService>();
    private Map<String,Thread> mapThread = new HashMap<String, Thread>();
	public synchronized static  MainControl getInstance(){
		if(mainControl == null){
			mainControl = new MainControl();
		}
		return mainControl;
	}
	public String getIdleSource(){
		for(Map.Entry<String,ThreadService> tt: mapThreads.entrySet()) {
			if (tt.getValue().isRun() == false)
				return tt.getKey();
		}
		return null;
	}

    public void updateSource(Map<String, Object> source){
        String sid = source.get("sourceID").toString();
        ThreadService ts =  mapThreads.get(sid);
        if(ts == null){
            ts = new ThreadService(source);
            mapThreads.put(sid,ts);
        }
        Thread t = mapThread.get(sid);
        if(t ==null) {
            t =  new Thread(ts);
            t.start();
            mapThread.put(sid,t);
        }else if(t.isAlive()==false){
            t = new Thread(ts);
            t.start();
            mapThread.put(sid,t);
        }
    }

    public synchronized InfoClassMap getInfoClassMap(Integer sourceID,Integer actionid){

        Map<Integer,InfoClassMap> mapI = sourceInfoMap.get(sourceID);
        if(mapI == null)
            return null;
        return mapI.get(actionid);
    }

    public synchronized Integer getActionIDbyName(Integer sourceID,String name){
        Map<Integer,InfoClassMap> mapI = sourceInfoMap.get(sourceID);
        if(mapI == null)
            return null;
        for(Map.Entry<Integer,InfoClassMap> ii: mapI.entrySet()){
            if(ii.getValue().equals(name)){
                return ii.getKey();
            }
        }
        return null;
    }
    public synchronized void updateInfoClassMap(String infoStr){

        JavaType javaType = MainControl.getCollectionType(ArrayList.class, InfoClassMap.class);
        List<InfoClassMap> lst = null;
        try {
            lst =  (List<InfoClassMap>)MainControl.mapper.readValue(infoStr, javaType);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if(lst == null)
            return;

        sourceInfoMap.clear();
        for(InfoClassMap icm : lst){
            Map<Integer,InfoClassMap> mInfo = sourceInfoMap.get(icm.getSourceID());
            if(mInfo == null){
                mInfo = new HashMap<Integer,InfoClassMap>();
                sourceInfoMap.put(icm.getSourceID(),mInfo);
            }

            InfoClassMap tInfo = mInfo.get(icm.getClassinfoID());

            if(tInfo == null){
                mInfo.put(icm.getClassinfoID(),icm);
            }
        }
    }

	public static void main(String[] args) throws UnknownHostException, InterruptedException {

        final CommandLineParser parser = new BasicParser();
        final Options options = new Options();
        options.addOption("s", "Scheduler", true, "Scheduler");
        options.addOption("a", "Submiter", true, "Submit URL");
        options.addOption("d", "DataService", true, "DataService URL");
        final CommandLine commandLine;
        try {
            commandLine = parser.parse(options, args);
        } catch (ParseException e) {
            e.printStackTrace();
            System.out.println("Parse command fails---解析输入命令失败");
            return;
        }


        if (commandLine.hasOption('s')) {
            schedulerAddr = commandLine.getOptionValue('s');
        } else {
            System.out.println("ERROR:scheduler address no exsit");
            return;
        }
        if (commandLine.hasOption('a')) {
            submitUrl = commandLine.getOptionValue('a');
            if (submitUrl.lastIndexOf('/') == submitUrl.length() - 1) {
                submitUrl = submitUrl.substring(0, submitUrl.length() - 1);
            }
        } else {
            System.out.println("ERROR:submit url  no  exsit");
            return;
        }

        if (commandLine.hasOption('d')) {
            dataServiceUrl = commandLine.getOptionValue('d');
            if (dataServiceUrl.lastIndexOf('/') == dataServiceUrl.length() - 1) {
                dataServiceUrl = dataServiceUrl.substring(0, dataServiceUrl.length() - 1);
            }
        } else {
            System.out.println("ERROR:data service url  no exsit");
            return;
        }
        Thread regThread = new Thread(new Runnable() {
            public void run() {
                MainControl main = MainControl.getInstance();
                while (true) {
                    try {
                        Register register = main.registerService();
                        sourceList = MainControl.configMissionCommons();
                        if (null == register) {
                            log.info("【程序退出】心跳请求失败,程序将退出!错误代码:000");
                        }
                        for (Map<String, Object> source : sourceList) {
                            System.out.println("新建线程" + source.get("webName").toString());
                            main.updateSource(source);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    try {
                        Thread.sleep(60 * 1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        regThread.start();

    }
    public static ObjectMapper mapper = new ObjectMapper();
    public static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
        return mapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
    }

	/**
	 * 向服务器提交一次心跳请求,每提交一次即为采集器的一次生命周期。<br/>
	 * 根据信源的数量决定每一次周期开启的线程数量,每一个线程对应一个站点的信源。<br/>
	 * 如果请求成功,将返回状态代码,如果请求异常,则停止服务。
	 */
	public Register registerService() {
		log.info("【系统】准备提交心跳请求...");
		String macAddress = IpConfigUtils.getMACAddress();
		log.info("\t------>Mac Address: \t" + macAddress);
		MACADDRESS = macAddress;
		String ip = IpConfigUtils.getNetIPAddress();
		log.info("\t------>IP Address: \t" + ip);
		// 拼接心跳参数
		String url = MainControl.schedulerAddr+"services/schedule/register";// 服务地址
		Map<String, String> param = new HashMap<String, String>();
		param.put("macaddr", macAddress);
		String responseValue = ConnectServer.sendPostRequest(url, JSON.toJSONString(param));
		if (StringUtil.isNullOrEmpty(responseValue)) {
			log.info("【系统】心跳请求异常,请检查网络连接!错误代码:102");
			return null;
		}

        missionMap = StringUtil.jsonToMap(responseValue);
        this.updateInfoClassMap((String)missionMap.get("infoClassMapList"));
		Register register = new Register();
		Map<String, Object> resultMap = StringUtil.jsonToMap(responseValue);
		register.setAlive(Integer.parseInt(resultMap.get("alive").toString()));
		register.setReg_result(Integer.parseInt(resultMap.get("reg").toString()));
		if (0 == register.getReg_result()) {
			log.info("【系统】心跳请求异常,请联系管理员!错误代码:103");
			return null;
		} else {
			log.info("【系统】心跳请求正常,开始执行本轮爬虫任务!");
		}
		return register;
	}

	/**
	 * 获取信源列表,如果列表为空,则返回null
	 * 
	 * @return
	 */
	public static List<Map<String, Object>> configMissionCommons() {
		List<Map<String, Object>> sourceMapList = MissionService.getSourceList();// 获取信源列表
		if (sourceMapList.size() == 0 || null == sourceMapList)
			log.info("【系统】获取信源列表失败,可能是网络连接异常!错误代码:104");
		else
			log.info("【系统】信源列表获取成功!");
		return sourceMapList;
	}

}

/**
 * 
 * @author TerransForce
 * 
 */
class Register {
	public int alive = 0;// 是否存活0否,1是
	public int reg_result = 0;// 是否注册成功0否,1是

	public int getAlive() {
		return alive;
	}

	public void setAlive(int alive) {
		this.alive = alive;
	}

	public int getReg_result() {
		return reg_result;
	}

	public void setReg_result(int reg_result) {
		this.reg_result = reg_result;
	}
}